<?php

/**
 *
 *
 * @version $Id$
 * @copyright 2013
 */

namespace com\org\web\tpl\utils {
	class TagAttrParser {
		 const PATTERN = "/(\\w+)\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\"'\\s>]*)/";

		 public static function parse($attribs) {
			 $org = $attribs = trim($attribs);
			 if (is_null($org) || strlen($org) === 0)
				 return NULL;
			 $matches = NULL;
			 $attrs = NULL;
			 preg_match_all(self::PATTERN, $attribs, $matches, PREG_SET_ORDER);
			 if ($matches !== NULL) {
			 	$attrs = array();
			 	foreach($matches as $match) {
					$attribs = str_replace($match[0], "", $attribs);
					if (($match[2][0] === "\"" || $match[2][0] === "'") && $match[2][0] === $match[2][strlen($match[2]) - 1])
					 	$match[2] = substr($match[2], 1, -1);
					$name = trim(strtolower($match[1]));
					$value = html_entity_decode($match[2]);
					if (String::startsWith($value, "$"))
						$value = trim($value, "$");
					$attrs[$name] = $value;
				}
			 }

			 $attribs = trim($attribs);
			 if ($attribs !== "")
				 throw new \Exception("parse: can't parse [$org] - not a properly formed attribute string");
			 return $attrs;
		 }
	}

	class TemplateVarParser {
		const PATTERN = "/\[\\s*(\"[^\"]*\"|'[^']*'|[^\"'\\s>]*)\\s*\]/";

		public static function parse($name) {
			$org = $name = trim($name);
			$pos = strpos($name, "[");
			$matches = NULL;
			$var = array();
			if ($pos > 0) {
				$var["name"] = substr($name, 0, $pos);
				$name = trim(substr($name, $pos));
			}
			else {
				$var["name"] = $name;
				$var["indice"] = NULL;
				return $var;
			}

			 preg_match_all(self::PATTERN, $name, $matches, PREG_SET_ORDER);
			 if ($matches !== NULL) {
				$var["indice"] = array();
				foreach($matches as $match) {
					$name = str_replace($match[0], "", $name);
					if (($match[1][0] === "\"" || $match[1][0] === "'") && $match[1][0] === $match[1][strlen($match[1]) - 1]) {
						$match[1] = substr($match[1], 1, -1);
						if (is_numeric($match[1]))
							$match[1] = intval($match[1]);
					}

					array_push($var["indice"], $match[1]);
				}
			 }

			 $name = trim($name);
			 if ($name !== "")
				 throw new \Exception("parse: can't parse [$org] - not a properly formed array index variable string");
			 return $var;
		}
	}

	class TemplateObjectParser {
		public static function parse($name) {
			$org = $name = trim($name);
			if (String::startsWith($name, "$"))
				$name = trim($name, "$");
			$names = explode("::", $name);
			$className = NULL;
			$methodNames = NULL;

			if (count($names) === 1) {
				$methodNames = $names[0];
			}
			else {
				$className = $names[0];
				$methodNames = $names[1];
			}

			$data = array();
			$data["class"] = $className;
			$data["trail"] = self::parseMethods($methodNames);

			return $data;
		}

		private static function parseMethods($text) {
			$data = explode("->", $text);
			$callees = array();
			if (count($data) === 1) {
				$callee = array();
				if (self::isMethod($data[0])) {
					$callee["property"] = FALSE;
					$callee["info"] = self::parseMethod($data[0]);
				}
				else {
					$callee["property"] = TRUE;
					$callee["info"]["name"] = $data[0];
				}

				$callees[0] = $callee;
			}
			else {
				$count = count($data);
				for ($i = 0; $i < $count; $i++) {
					$callee = array();
					if (self::isMethod($data[$i])) {
						$callee["property"] = FALSE;
						$callee["info"] = self::parseMethod($data[$i]);
					}
					else {
						$callee["property"] = TRUE;
						$callee["info"]["name"] = $data[$i];
					}

					$callees[$i] = $callee;
				}
			}

			return $callees;
		}

		private static function parseMethod($prototype) {
			$prototype = trim($prototype);
			$prototype = trim($prototype, ")");
			$pos = strpos($prototype, "(");
			$name = substr($prototype, 0, $pos);
			$text = substr($prototype, $pos + 1);
			$method = array();
			$method["name"] = $name;
			$method["args"] = self::parseMethodArgs($text);

			return $method;
		}

		private static function parseMethodArgs($text) {
			$test = trim($text);
			$arg = array();
			$args = array();
			$len = strlen($text);
			$i = 0;
			$pos = 0;
			while($len > 0) {
				$pos = self::getFirstValidCommaPos($text);
				if(String::startsWith($text, "$")) {
					if ($pos > 0) {
						$arg["var"] = TRUE;
						$arg["value"] = trim(substr($text, 1, $pos));
						$args[$i] = $arg;
						$text = trim(substr($text, $pos + 1));
					}
					else {
						$arg["var"] = TRUE;
						$arg["value"] = trim(substr($text, 1));
						$args[$i] = $arg;
						$text = "";
					}
				}
				else {
					if ($pos > 0) {
						$arg["var"] = FALSE;
						$arg["value"] = self::stripBackSlash(trim(substr($text, 0, $pos)));
						$args[$i] = $arg;
						$text = trim(substr($text, $pos + 1));
						$i++;
					}
					else {
						$arg["var"] = FALSE;
						$arg["value"] = self::stripBackSlash(trim($text));
						$args[$i] = $arg;
						$text = "";
					}
				}

				$len = strlen($text);
				$i++;
			}

			return $args;
		}

		private static function isMethodCall($name) {
			if (strpos($name, "->") > 0)
				return TRUE;
			return FALSE;
		}

		private static function isMethod($name) {
			if (strpos($name, "(") > 0 && String::endsWith($name, ")"))
				return TRUE;
			return FALSE;
		}

		private static function getFirstValidCommaPos($text) {
			$pos = strpos($text, ",");
			$subPos = strpos($text, "\\");
			while(($pos === $subPos + 1) && ($pos > 0)) {
				$pos = strpos($text, ",", $pos + 1);
				if ($pos !== FALSE)
					$subPos = strpos($text, "\\", $pos - 1);
			}

			return $pos;
		}

		private static function stripBackSlash($text) {
			$pos = strpos($text, ",");
			$subPos = strpos($text, "\\");
			while(($pos === $subPos + 1) && ($pos > 0)) {
				$text = substr($text, 0, $subPos) . substr($text, $subPos + 1);
				$subPos = strpos($text, "\\");
				$pos = strpos($text, ",", $subPos);
			}

			return $text;
		}
	}
}
?>